package com.mstar.qs.common;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * xpath string have to start with "/"
 * 
 * @author dchen2
 * 
 */
public class EntryHelper {

	public static final String pe = "/";

	public static String traverseAttribute(String module, Entry entry,
			String key) {
		if (module == null || module.trim().length() == 0 || entry == null
				|| key == null || key.trim().length() == 0)
			throw new NullPointerException();
		String v = entry.attribute(key);
		if (v != null)
			return v;
		List<Entry> es = entry.retrieveSubEntries(module);
		if (es == null)
			return null;
		Iterator<Entry> it = es.iterator();
		while (it.hasNext()) {
			Entry e = it.next();
			v = traverseAttribute(e, key);
			if (v != null)
				return v;
		}
		return null;
	}

	public static String traverseAttribute(Entry entry, String key) {
		if (entry == null || key == null || key.trim().length() == 0)
			throw new NullPointerException();
		String v = entry.attribute(key);
		if (v != null)
			return v;
		Map<String, List<Entry>> sub = entry.getEntries();
		if (sub == null || sub.size() == 0)
			return null;
		for (Map.Entry<String, List<Entry>> sc : sub.entrySet()) {
			List<Entry> les = sc.getValue();
			v = traverseAttribute(les, key);
			if (v != null)
				return v;
		}
		return null;
	}

	private static String traverseAttribute(List<Entry> les, String key) {
		String v = null;
		for (Entry e : les) {
			v = traverseAttribute(e, key);
			if (v != null)
				return v;
		}
		return null;
	}

	public static String attributeCross(Entry node, String xpath,
			String attribute) {
		if (node == null || xpath == null || attribute == null)
			throw new NullPointerException();

		if(xpath.endsWith("/"))
			xpath=xpath.substring(0,xpath.length()-1);
		
		if (xpath.indexOf("/") == 0)
			xpath = xpath.substring(1);

		String[] xp = xpath.split(pe);
		String en = xp[0];
		if (xp.length == 1) {
			if (node.getElementName().equals(en))
				return node.attribute(attribute);
		} else {
			if (node.getElementName().equals(en)) {
				List<Entry> ses = node.retrieveSubEntries(xp[1]);
				String np = xpath.substring(xp[0].length());
				for (Entry e : ses) {
					String v = attributeCross(e, np, attribute);
					if (v != null)
						return v;
				}
			} else {
				throw new IllegalArgumentException(
						"Cannot match the specified xpath:" + xpath);
			}
		}
		return null;

	}

	public static String textCross(Entry node, String xpath) {
		if (node == null || xpath == null)
			throw new NullPointerException();
		if(xpath.endsWith("/"))
			xpath=xpath.substring(0,xpath.length()-1);
		if (xpath.indexOf(pe) == 0)
			xpath = xpath.substring(1);
		String[] xp = xpath.split(pe);
		// String en=xp[0];
		if (xp.length == 1) {
			if (node.getElementName().equals(xp[0]))
				return node.getValue();
		} else {
			if (node.getElementName().equals(xp[0])) {
				List<Entry> ses = node.retrieveSubEntries(xp[1]);
				if (ses == null)
					throw new IllegalArgumentException(
							"Cannot match the specified xpath. xpath:" + xpath);
				for (Entry e : ses) {
					String np = xpath.substring(xp[0].length());
					String v = textCross(e, np);
					if (v != null)
						return v;
				}
			} else {
				throw new IllegalArgumentException(
						"Cannot match the specified xpath:" + xpath);
			}
		}
		return null;

	}

	/**
	 * obtain entries along with the specified path starting with slash /. each
	 * element name is split by slash /.
	 * 
	 * @param node
	 * @param xpath
	 * @return
	 */
	public static List<Entry> entriesCross(Entry node, String xpath) {
		if (node == null || xpath == null)
			throw new NullPointerException();
		if (xpath.indexOf("/") == 0)
			xpath = xpath.substring(1);
		if(xpath.endsWith("/"))
			xpath=xpath.substring(0,xpath.length()-1);
		String[] xp = xpath.split(pe);
		String en = xp[0];
		if (xp.length == 2) {
			if (node.getElementName().equals(en))
				return node.retrieveSubEntries(xp[1]);
		} else {
			if (node.getElementName().equals(en)) {
				List<Entry> ses = node.retrieveSubEntries(xp[1]);
				for (Entry e : ses) {
					String np = xpath.substring(xp[0].length());
					List<Entry> se = entriesCross(e, np);
					if (se != null)
						return se;
				}
			} else {
				throw new IllegalArgumentException(
						"Cannot match the specified xpath:" + xpath);
			}
		}

		return null;
	}

	/**
	 * obtain second element. if having more than one second level elements with
	 * specified element name, the first element is returned.
	 * 
	 * @param e
	 * @param moduleName
	 * @return
	 */
	public static Entry secondEntry(Entry e, String moduleName) {
		List<Entry> le = e.secondEntries(moduleName);
		if (le != null && le.size() > 0)
			return le.get(0);
		return null;
	}

	/**
	 * obtain second elements with specified moduleName.
	 * 
	 * @param e
	 * @param moduleName
	 * @return
	 */
	public static List<Entry> secondEntries(Entry e, String moduleName) {
		return e.secondEntries(moduleName);
	}

	/**
	 * obtain third element. if having more than one second level or third level
	 * elements with specified second element name or third element name, the
	 * first element is returned.
	 * 
	 * @param e
	 * @param moduleName
	 * @return
	 */
	public static Entry thirdEntry(Entry e, String moduleName,
			String subModuleName) {
		Entry en = secondEntry(e, moduleName);
		if (en == null)
			return null;
		return secondEntry(en, subModuleName);
	}

	/**
	 * obtain third elements. If having more than one second level elements,
	 * only obtain from the first second level element.
	 * 
	 * @param e
	 * @param moduleName
	 * @param subModuleName
	 * @return
	 */
	public static List<Entry> thirdEntries(Entry e, String moduleName,
			String subModuleName) {
		Entry en = secondEntry(e, moduleName);
		if (en == null)
			return null;
		return secondEntries(en, subModuleName);
	}
}
